package xml.sax.plm;

import java.io.ByteArrayInputStream;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;

import javax.xml.bind.JAXBElement;
import javax.xml.bind.Marshaller;
import constants.Globals;
import exception.IBToolsException;

import structures.xmltable.ServiceBaseTypeParameter;
import structures.xmltable.ServiceParameterTable;
import structures.xmltable.ServiceRcOutBaseTypeParameter;
import structures.xmltable.ServiceRcOutTableTypeParameter;
import structures.xmltable.ServiceTableColumn;
import structures.xmltable.ServiceTableTypeParameter;
import structures.xmltable.ServiceTableValue;

import xml.sax.ClassNameLoader;
import xml.sax.JaxbUtil;
import xml.sax.plm.RC.*;

public class PlmInXMLProcessor implements Globals {

	private static JaxbUtil jaxbUtil;
	
	public static void utilize(){
        String name = ClassNameLoader.getPackageName(new Object() {}.getClass());
        
		jaxbUtil = new JaxbUtil(name);
		jaxbUtil.setRemoveXmlHeaderTag(true);
		jaxbUtil.addMarshallProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
	}

    
    public static String getXmlServiceName(String xmlString){
    	if(jaxbUtil == null)
    		utilize();
    	xmlString = xmlString.replaceAll("&", "&amp;");
        ByteArrayInputStream input = new ByteArrayInputStream (xmlString.getBytes(Charset.forName("UTF8"))); 
        RC rc = (RC) jaxbUtil.unmarshal(input);
        return rc.getS();
    }
    
    public static String convertTableToXml(ServiceParameterTable table, boolean addSessionInfo) throws IBToolsException {
    	if(jaxbUtil == null)
    		utilize();
    	String xml = "";
    	
    	RC rc = new RC();
    	rc.setS(table.getServiceName());
    	rc.i = new I();
    	rc.i.p = new ArrayList<RC.I.P>();
    	rc.o = new O();
    	rc.o.p = new ArrayList<RC.O.P>();
    	
//    	if(addSessionInfo){
//    		RC.I.P phead = new RC.I.P();
//    		phead.setN("SESSION_KULLANICIKODU");
//    		phead.content = new ArrayList<>();
//    		phead.content.add(table.getHeaderInfo().getUid());
//    		rc.i.p.add(phead);
//
//    		phead = new RC.I.P();
//    		phead.setN("SESSION_CHANNELCODE");
//    		phead.content = new ArrayList<>();
//    		phead.content.add(table.getHeaderInfo().getFcid());
//    		rc.i.p.add(phead);
//    	}
    	
    	for (Object param : table.getServiceBaseTypeParameters()) {
			if(param instanceof ServiceRcOutBaseTypeParameter){
				ServiceRcOutBaseTypeParameter parameter = (ServiceRcOutBaseTypeParameter) param;
				addBaseParameter(parameter, rc, parameter.getIdValue());
			}
			else if(param instanceof ServiceRcOutTableTypeParameter){
				ServiceRcOutTableTypeParameter tableParameter = (ServiceRcOutTableTypeParameter) param;
				addTableParameter(tableParameter, rc, tableParameter.getIdValue());
			}
			else if(param instanceof ServiceTableTypeParameter){
				ServiceTableTypeParameter tableParameter = (ServiceTableTypeParameter) param;
				addTableParameter(tableParameter, rc, tableParameter.getBagKey());
			}
			else if(param instanceof ServiceBaseTypeParameter){
				ServiceBaseTypeParameter parameter = (ServiceBaseTypeParameter) param;
				addBaseParameter(parameter, rc, parameter.getBagKey());
			}
		}
    	
		xml = jaxbUtil.marshal(rc);
		return xml.replaceAll("&amp;", "&");
    }
    private static void addBaseParameter(ServiceBaseTypeParameter parameter, RC rc, String idValue){
		if(parameter.isActive()){
			if(parameter.isInput()){
				RC.I.P p = new RC.I.P();
				p.setN(parameter.getBagKey());
				p.content = new ArrayList<>();
				p.content.add(parameter.getValue());
				rc.i.p.add(p);
			}
			else {
				RC.O.P p = new RC.O.P();
				p.setN(parameter.getBagKey());
				p.setId(idValue);
				p.setValue(parameter.getValue());
				rc.o.p.add(p);
			}
		}
    }
    private static void addTableParameter(ServiceTableTypeParameter tableParameter, RC rc, String idValue){

		if(tableParameter.isActive()){
			if(!tableParameter.isInput()){
				RC.O.P p = new RC.O.P();
				p.setN(tableParameter.getBagKey());
//				p.setId(tableParameter.getIdValue());
				p.setId(idValue);
				if(tableParameter.getDim() == null)
					p.setDim("2");
				else
					p.setDim(tableParameter.getDim());
				p.setValue(tableParameter.getValue());
				rc.o.p.add(p);
			}
			else {
				int index = 0;
				int colIndex = 0;
				RC.I.P p = new RC.I.P();
				p.setN(tableParameter.getBagKey());
				boolean isArray = false;
				if(tableParameter.getColumns().size() == 1 && 
						(tableParameter.getColumns().get(0).getColumnName() == null ||
						tableParameter.getColumns().get(0).getColumnName().equals(Globals.EMPTY_STRING))){
					isArray = true;
				}
				if(tableParameter.getDim() == null){
					if(isArray)
						p.setDim("1");
					else
						p.setDim("2");
				}
				else
					p.setDim(tableParameter.getDim());
				for (List<ServiceTableValue> columnValues : tableParameter.getValues()) {
					for (ServiceTableValue value : columnValues) {
//						if( !value.equalsIgnoreCase("..kill_..")){
							ServiceTableColumn column = tableParameter.getColumns().get(index);
							RC.I.P.D d = new RC.I.P.D();
							if(!isArray){
								d.c = column.getColumnName();
								d.r = colIndex;
							}
							d.value = value.toString();
							index++;
					        ObjectFactory objectFactory = new ObjectFactory();
			                JAXBElement<RC.I.P.D> paramD = objectFactory.createRCIPD(d);
							p.getContent().add(paramD);
//						}
					}
					index = 0;
					colIndex ++;
				}
				rc.i.p.add(p);
			}
		}
	
    }
    
    public static ServiceParameterTable convertXmlToTable(String xmlString) throws IBToolsException {
    	if(jaxbUtil == null)
    		utilize();

    	xmlString = xmlString.replaceAll("&", "&amp;");
        ByteArrayInputStream input = new ByteArrayInputStream (xmlString.getBytes(Charset.forName("UTF8"))); 
        RC rc = (RC) jaxbUtil.unmarshal(input);

        List<ServiceBaseTypeParameter> parameters = new ArrayList<ServiceBaseTypeParameter>();
        List<ServiceTableTypeParameter> tables = new ArrayList<ServiceTableTypeParameter>();

        List<ServiceTableColumn> currentColumns = null;
        
        if(rc.getI() != null){
        	for (RC.I.P p : rc.getI().getP()) {
        		List<?> arrayParameterList = (ArrayList<?>) p.getContent();
        		boolean isTable = false;
        		if(p.getDim() != null && new Integer(p.getDim()) > 0){
					isTable = true;
        		}
        		else {
            		for (Object object : arrayParameterList) {
    					if(object instanceof JAXBElement<?>){
    						isTable = true;
    						break;
    					}
    				}
        		}
        		if(isTable){
        			ServiceTableTypeParameter tableParam = new ServiceTableTypeParameter(
                        	p.getN(), EMPTY_STRING, EMPTY_STRING, true, true, false);
        			tableParam.setDim(p.getDim());
        			
                    List<List<ServiceTableValue>> tlist = new ArrayList<List<ServiceTableValue>>();

        			Integer currentLine = null;
        			int colSize = 0;
        			currentColumns = new ArrayList<ServiceTableColumn>();

                    for (int i = 0 ; i < arrayParameterList.size() ; i ++) {
    					if(arrayParameterList.get(i) instanceof JAXBElement<?>){
                            JAXBElement<?> paramD = (JAXBElement<?>) arrayParameterList.get(i);
                            RC.I.P.D d = (RC.I.P.D) paramD.getValue();
            				if(currentLine == null){
            					currentLine = d.getR();
            				}
            				else if(!currentLine.equals(d.getR())){
            					break;
            				}
            				colSize++;
    					}
                    }
                    
                    boolean columnsSet = false;
        			currentLine = null;
                    for (int i = 0 ; i < arrayParameterList.size() ; i ++) {
    					if(arrayParameterList.get(i) instanceof JAXBElement<?>){
    						JAXBElement<?> paramD = (JAXBElement<?>) arrayParameterList.get(i);
    						RC.I.P.D d = (RC.I.P.D) paramD.getValue();
    						if(currentLine == null){
	        					currentLine = d.getR();
	        				}
	        				else if( !currentLine.equals(d.getR())){
	        					columnsSet = true;
	        					currentLine = d.getR();
	        				}
	        				Integer rInt = (d.getR() == null) ? 0 : new Integer(d.getR());
	        				if(tlist.size() == rInt)
	        					tlist.add(new ArrayList<ServiceTableValue>(colSize));
	                		tlist.get(rInt).add(new ServiceTableValue(d.getValue()));
	        				if(!columnsSet)
	        					currentColumns.add(new ServiceTableColumn(null, d.getC(), currentColumns.size()));
    					}
        			}

                    tableParam.setValues(tlist);
                    tableParam.loadColumns(currentColumns);
                    tables.add(tableParam);
        		}
        		else {
            		String objectTemp = "";
        			if(arrayParameterList == null || arrayParameterList.size() == 0)
        				objectTemp = EMPTY_STRING;
        			else
        				objectTemp = arrayParameterList.get(0).toString();
        			if( !p.getN().equals("SESSION_KULLANICIKODU") && !p.getN().equals("SESSION_CHANNELCODE")){
                    	ServiceBaseTypeParameter param = new ServiceBaseTypeParameter(
                    			p.getN(), objectTemp.toString(), EMPTY_STRING, true, true, PARAM_STRING);
        	        	param.analyzeType();
        	        	param.analyzeValue();
                    	parameters.add(param);
        			}
        		}
			}
        }
        if(rc.getO() != null){
        	for (RC.O.P p : rc.getO().getP()) {
        		if(p.getDim() != null && new Integer(p.getDim()) > 0){
                	parameters.add(new ServiceRcOutTableTypeParameter(p.getN(), p.getId(), p.getDim()));
        		}
        		else {
                	parameters.add(new ServiceRcOutBaseTypeParameter(
                			p.getN(), p.getValue(), EMPTY_STRING, true, false, PARAM_STRING, p.getId()));
        		}
        	}
        }
        
        ServiceParameterTable serviceParameterTable = new ServiceParameterTable();
        serviceParameterTable.setServicename(rc.getS());
        
        for (ServiceBaseTypeParameter serviceBaseTypeParameter : parameters) {
        	serviceParameterTable.add(serviceBaseTypeParameter);
		}
        for (ServiceTableTypeParameter newServiceTableTypeParameter : tables) {
        	serviceParameterTable.add(newServiceTableTypeParameter);
		}
        
        return serviceParameterTable;
    }
    
    public static String simpleFormat(String xmlString){
    	if(jaxbUtil == null)
    		utilize();
        ByteArrayInputStream input = new ByteArrayInputStream (
        		xmlString
        		.replaceAll("\r\n ", "")
        		.replaceAll("&", "&amp;")
        		.getBytes(Charset.forName("UTF8"))); 
        RC rc = (RC) jaxbUtil.unmarshal(input);
        xmlString = jaxbUtil.marshal(rc);
        return xmlString.replaceAll("&amp;", "&");
    }
}
